<template>
  <canvas ref="render" class="model-shower"></canvas>
</template>
<script>
import * as THREE from 'three/build/three.module'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
const loader = new GLTFLoader()
// import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass'
// import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
// import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper'
import { ref } from 'vue'
export default {
  props: {
    src: {
      type: String,
      default: ''
    },
    rotate: {
      type: Array,
      default: () => [0, 0]
    }
  },
  setup() {
    const fadeOpen = ref(false)
    return {
      render: null,
      modelObject: null,
      camera: null,
      scene: null,
      material: null,
      control: null,
      fadeOpen,
      frameMaterial: null
    }
  },
  watch: {
    curIndex() {
      this.fadeOpen = true
      setTimeout(() => {
        this.fadeOpen = false
      }, 300)
    }
  },
  methods: {
    initScene() {
      this.scene = new THREE.Scene()
    },
    initMaterial() {
      this.material = new THREE.ShaderMaterial({
        uniforms: {
          scale: { value: 0.89 }
        },
        vertexShader: require('./shaders/v.glsl').default,
        fragmentShader: require('./shaders/f.glsl').default
      })
      this.frameMaterial = new THREE.ShaderMaterial({
        uniforms: {
          scale: { value: 1.09 }
        },
        wireframe: true,
        wireframeLinejoin: 'bevel',
        wireframeLinewidth: 1.5,
        vertexShader: require('./shaders/v.glsl').default,
        fragmentShader: require('./shaders/fshow.glsl').default
      })
    },
    initLight() {
      const spotLight = new THREE.SpotLight(0x111111, 4)
      spotLight.position.set(8, 8, 8)
      spotLight.castShadow = true

      spotLight.shadow.mapSize.width = 1
      spotLight.shadow.mapSize.height = 1

      spotLight.shadow.camera.near = 10
      spotLight.shadow.camera.far = 40
      spotLight.shadow.camera.fov = 10
      const light = new THREE.AmbientLight(0xffffff, 0.02) // soft white light
      this.scene.add(light)
      this.scene.add(spotLight)
    },
    initRender() {
      const width = this.$refs.render.clientWidth
      const height = this.$refs.render.clientHeight * 0.8
      this.camera = new THREE.PerspectiveCamera(50, width / height, 0.1, 1000)
      this.camera.position.set(5, 5, 5)
      this.camera.lookAt(0, 0, 0)

      const renderer = new THREE.WebGLRenderer({
        canvas: this.$refs.render,
        setPixelRatio: 2,
        antialias: true,
        alpha: true,
        precision: 'highp'
      })

      renderer.setFaceCulling(THREE.CullFaceBack, THREE.FrontFaceDirectionCW)
      renderer.setSize(width, height)
      this.render = renderer
    },
    loadModel(url) {
      return new Promise((resolve, reject) => {
        loader.load(
          url,
          function(gltf) {
            console.log(gltf)
            resolve(gltf)
          },
          undefined,
          function(error) {
            reject(error)
          }
        )
      })
    },

    addModelToScene() {
      try {
        const object = this.modelObject.scene
        const normalObject = object.clone()
        // normalObject.children.forEach(item => {
        //   item.material = this.material
        // })
        const wireframe = object.clone()
        wireframe.children.forEach(item => {
          item.material = this.frameMaterial
        })
        normalObject.position.set(-1, -1, 1)
        wireframe.position.set(-1, -1, 1)
        this.scene.add(normalObject)
        this.scene.add(wireframe)
        return true
      } catch (e) {
        return false
      }
    },
    draw() {
      this.scene.rotation.x = this.rotate[1]
      this.scene.rotation.y = this.rotate[0]
      this.render.render(this.curScene, this.camera)
      // this.control.update()
      requestAnimationFrame(this.draw)
    }
  },
  async mounted() {
    this.initMaterial()
    this.initRender()
    this.initScene()

    this.curScene = this.scene
    const res = await this.loadModel(this.src)
    this.modelObject = res
    this.initLight()
    // this.control = new OrbitControls(this.camera, this.render.domElement)
    this.addModelToScene() && this.draw()
  }
}
</script>
<style lang="less" scoped>
.model-shower {
  pointer-events: none;
  @apply bg-transparent;
  width: 20rem;
  height: 25rem;
  z-index: 1;
}
</style>
